using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UMC.Data;

namespace UMC.Net
{

    public class HeadValues : IDisposable
    {
        private bool _Isurlencoded;
        public void Clear()
        {
            _headSize = 0;
        }
        public bool IsUrlEncoded => _Isurlencoded;
        public HeadValues() { }

        public HeadValues(bool Isurlencoded)
        {
            _Isurlencoded = Isurlencoded;
        }
        public ReadOnlySpan<HeadValue> Span
        {
            get
            {
                return _headValues.AsSpan(0, _headSize);
            }
        }
        public bool TryGet(ReadOnlySpan<byte> name, out HeadValue headValue)
        {
            for (var i = 0; i < _headSize; i++)
            {
                if (Utility.EqualIgnoreCase(_headValues[i].Name.Span, name))
                {
                    headValue = _headValues[i];
                    return true;

                }
            }
            headValue = null;
            return false;
        }
        public int Count => _headSize;
        int _headSize = 0;
        HeadValue[] _headValues = ArrayPool<HeadValue>.Shared.Rent(8);

        public override String ToString()
        {
            var sb = new StringBuilder();
            foreach (var h in this.Span)
            {
                sb.Append(h.Name.Span.UTF8());
                sb.Append(": ");
                sb.Append(h.Value.Span.UTF8());
                sb.Append("\r\n");
            }
            return sb.ToString();
        }

        public int BytesSize
        {
            get
            {
                var size = 0;
                for (var i = 0; i < _headSize; i++)
                {
                    size += _headValues[i].Length;
                }
                return size;

            }
        }
        public void Remove(ReadOnlySpan<byte> key)
        {
            for (var i = 0; i < _headSize; i++)
            {
                if (Utility.EqualIgnoreCase(_headValues[i].Name.Span, key))
                {
                    Array.Copy(_headValues, i + 1, _headValues, i, _headSize - i - 1);
                    _headSize--;
                }
            }
        }
        public void Add(HeadValue headValue)
        {

            if (_headValues.Length == _headSize)
            {
                var hvs = ArrayPool<HeadValue>.Shared.Rent(_headValues.Length + 8);
                Array.Copy(_headValues, 0, hvs, 0, _headSize);
                ArrayPool<HeadValue>.Shared.Return(_headValues, true);
                _headValues = hvs;

            }

            _headValues[_headSize] = headValue;
            _headSize++;
        }

        public void Dispose()
        {
            if (this._headValues.Length > 0)
                System.Buffers.ArrayPool<HeadValue>.Shared.Return(this._headValues, true);
            this._headValues = Array.Empty<HeadValue>();
            _headSize = 0;
        }
        public StringValue[] GetValues(ReadOnlySpan<byte> key)
        {
            var span = this.Span;

            var ls = new List<StringValue>();
            foreach (var k in span)
            {
                if (Utility.EqualIgnoreCase(k.Name.Span, key))
                {
                    ls.Add(k.Value);

                }
            }
            return ls.ToArray();

        }
        public String Get(String key)
        {
            var sKey = key.UTF8();
            foreach (var k in this.Span)
            {
                if (Utility.EqualIgnoreCase(k.Name.Span, sKey))
                {
                    if (this._Isurlencoded)
                    {
                        String value = String.Empty;

                        k.Value.Output((b, i, c) => value = System.Net.WebUtility.UrlDecodeToBytes(b, i, c).UTF8());
                        //  k.Value.Output()
                        return value;
                    }
                    return k.Value.Span.UTF8();


                }
            }
            return null;
        }
        public StringValue Get(ReadOnlySpan<byte> key)
        {
            foreach (var k in this.Span)
            {
                if (Utility.EqualIgnoreCase(k.Name.Span, key))
                {
                    return k.Value;

                }
            }
            return StringValue.Empty;
        }
        //  public StringValue this[MimeHeadKey headKey]
        // {
        //     get
        //     {
        //         return Get(name);
        //     }
        //     set
        //     {
        //         this[new StringValue(name)] = value;
        //     }
        // }

        public StringValue this[byte[] name]
        {
            get
            {
                return Get(name);
            }
            set
            {
                this[new StringValue(name)] = value;
            }
        }
        public StringValue this[StringValue name]
        {
            get
            {
                return Get(name.Span);
            }
            set
            {
                var IsAdd = true;
                for (var i = 0; i < _headSize; i++)
                {
                    if (Utility.EqualIgnoreCase(_headValues[i].Name.Span, name.Span))
                    {
                        if (IsAdd && value.IsEmpty == false)
                        {
                            IsAdd = false;
                            _headValues[i] = new HeadValue(_headValues[i]);
                            _headValues[i].Value = value;

                        }
                        else
                        {
                            Array.Copy(_headValues, i + 1, _headValues, i, _headSize - i - 1);
                            _headSize--;
                            i--;

                        }
                    }
                }

                if (IsAdd)
                {
                    this.Add(new HeadValue(name, value));
                }
            }
        }
        public String this[String name]
        {
            get
            {
                return Get(name);
            }
            set
            {
                this[new StringValue(UTF8Encoding.UTF8.GetBytes(name))] = new StringValue(value);
            }
        }
        public StringValue this[ReadOnlySpan<byte> name]
        {
            get
            {
                return Get(name);
            }
            set
            {
                this[new StringValue(name.ToArray())] = value;
            }
        }
    }

}
